﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Forms;
using System.Windows.Input;
using System.Windows.Interop;
using Application = System.Windows.Application;
using MessageBox = System.Windows.MessageBox;

namespace WPFPractice.Utils
{
    public partial class OskOpr
    {
        private static Process softKey;

        public static void ShowOsk(FrameworkElement ele)
        {
            var p = ele.PointToScreen(new Point(0, 0));
            //打开软键盘
            try
            {
                if (!File.Exists(Environment.SystemDirectory + "\\osk.exe"))
                {
                    MessageBox.Show("软件盘可执行文件不存在！");
                    return;
                }
                //C:\\Windows\\System32\\osk.exe
                //C:\\Program Files\\Common Files\\microsoft shared\\ink\\TabTip.exe
                softKey = Process.Start("C:\\Windows\\System32\\osk.exe");
                // 上面的语句在打开软键盘后，系统还没用立刻把软键盘的窗口创建出来了。所以下面的代码用循环来查询窗口是否创建，只有创建了窗口
                // FindWindow才能找到窗口句柄，才可以移动窗口的位置和设置窗口的大小。这里是关键。
                IntPtr intptr = IntPtr.Zero;
                while (IntPtr.Zero == intptr)
                {
                    Thread.Sleep(100);
                    //Microsoft Text Input Application
                    //屏幕键盘
                    intptr = NativeMethods.FindWindow(null, "屏幕键盘");
                }

                // 获取屏幕尺寸
                int iActulaWidth = Screen.PrimaryScreen.Bounds.Width;
                int iActulaHeight = Screen.PrimaryScreen.Bounds.Height;

                // 设置软键盘的显示位置，底部居中
                int posX = (int)p.X;
                int posY = (int)p.Y;

                //设定键盘显示位置
                NativeMethods.MoveWindow(intptr, posX, posY, 1000, 300, true);

                //设置软键盘到前端显示
                NativeMethods.SetForegroundWindow(intptr);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }

        public static void ShowTabTip(FrameworkElement ele)
        {
            //切换输入法

            var p = ele.PointToScreen(new Point(0, 0));
            var handle = new WindowInteropHelper(Application.Current.MainWindow).Handle;
            Task.Run(delegate
            {
                //打开软键盘
                try
                {
                    if (!File.Exists(Environment.SystemDirectory + "\\osk.exe"))
                    {
                        MessageBox.Show("软件盘可执行文件不存在！");
                        return;
                    }
                    //C:\\Windows\\System32\\osk.exe
                    //C:\\Program Files\\Common Files\\microsoft shared\\ink\\TabTip.exe
                    softKey = Process.Start("C:\\Program Files\\Common Files\\microsoft shared\\ink\\TabTip.exe");
                    // 上面的语句在打开软键盘后，系统还没用立刻把软键盘的窗口创建出来了。所以下面的代码用循环来查询窗口是否创建，只有创建了窗口
                    // FindWindow才能找到窗口句柄，才可以移动窗口的位置和设置窗口的大小。这里是关键。
                    IntPtr intptr = IntPtr.Zero;
                    while (IntPtr.Zero == intptr)
                    {
                        Thread.Sleep(100);
                        //Microsoft Text Input Application
                        //屏幕键盘
                        intptr = NativeMethods.FindWindow(null, "Microsoft Text Input Application");
                    }


                    // 获取屏幕尺寸
                    int iActulaWidth = Screen.PrimaryScreen.Bounds.Width;
                    int iActulaHeight = Screen.PrimaryScreen.Bounds.Height;


                    // 设置软键盘的显示位置，底部居中
                    int posX = (int)p.X;
                    int posY = (int)p.Y;
                    //TouchKeyboard.SetWin10TouchKeyboardPosition(posX, posY);

                    Thread.Sleep(300);

                    NativeMethods.GetWindowRect(intptr, out var r);
                    var w = r.Right - r.Left; var h = r.Bottom - r.Top;
                    //设定键盘显示位置
                    NativeMethods.MoveWindow(intptr, posX, posY, w, h, false);
                    //NativeMethods.SetWindowPos(intptr, handle, posX, posY, w, h, 0x0045);


                    //设置软键盘到前端显示
                    //SetForegroundWindow(intptr);
                }
                catch (Exception ex)
                {
                    MessageBox.Show(ex.Message);
                }
            });
        }

        /// <summary>
        /// 切换输入法到安装语言的系统自带输入法
        /// </summary>
        public static void SwitchLocalLanguage()
        {
            var cur = CultureInfo.CurrentCulture;
            var langIDs = Enumerable.ToList<short>(GetLangIDs());
            var i = langIDs.FindIndex(x => x == cur.KeyboardLayoutId);
            if (i != -1)
            {
                string[] list = GetAvalivableInputMethodDesc(langIDs[i]);
                if (list.Length > 1)
                {
                    //var all = TSFWrapper.GetAllInputMethodDesc(langIDs[i]);
                    //一定要先切换成系统默认的输入法，才能再切其他输入法
                    InputLanguageManager.Current.CurrentInputLanguage = cur;
                    ActiveInputMethodWithDesc(langIDs[i], list.Last());
                }
                else
                {
                    //var all = InputLanguageManager.Current.AvailableInputLanguages.Cast<CultureInfo>();
                    InputLanguageManager.Current.CurrentInputLanguage = cur;
                }

            }
        }

        public static short[] GetLangIDs()
        {
            List<short> langIDs = new List<short>();
            TSF_NativeAPI.ITfInputProcessorProfiles profiles;
            if (TSF_NativeAPI.TF_CreateInputProcessorProfiles(out profiles) == 0)
            {
                IntPtr langPtrs;
                int fetchCount = 0;
                if (profiles.GetLanguageList(out langPtrs, out fetchCount) == 0)
                {
                    for (int i = 0; i < fetchCount; i++)
                    {
                        short id = Marshal.ReadInt16(langPtrs, sizeof(short) * i);
                        langIDs.Add(id);
                    }
                }
                Marshal.ReleaseComObject(profiles);
            }
            return langIDs.ToArray();
        }

        public static bool ActiveInputMethodWithDesc(short langID, string desc)
        {
            TSF_NativeAPI.ITfInputProcessorProfiles profiles;
            if (TSF_NativeAPI.TF_CreateInputProcessorProfiles(out profiles) == 0)
            {
                try
                {
                    TSF_NativeAPI.IEnumTfLanguageProfiles enumerator = null;
                    if (profiles.EnumLanguageProfiles(langID, out enumerator) == 0)
                    {
                        if (enumerator != null)
                        {
                            TSF_NativeAPI.TF_LANGUAGEPROFILE[] langProfile = new TSF_NativeAPI.TF_LANGUAGEPROFILE[1];
                            int fetchCount = 0;
                            while (enumerator.Next(1, langProfile, out fetchCount) == 0)
                            {
                                IntPtr ptr;
                                if (profiles.GetLanguageProfileDescription(ref langProfile[0].clsid, langProfile[0].langid, ref langProfile[0].guidProfile, out ptr) == 0)
                                {
                                    bool enabled;
                                    if (profiles.IsEnabledLanguageProfile(ref langProfile[0].clsid, langProfile[0].langid, ref langProfile[0].guidProfile, out enabled) == 0)
                                    {
                                        if (enabled)
                                        {
                                            string s = Marshal.PtrToStringBSTR(ptr);
                                            if (s.Equals(desc))
                                                return profiles.ActivateLanguageProfile(ref langProfile[0].clsid, langProfile[0].langid, ref langProfile[0].guidProfile) == 0;
                                        }
                                    }
                                    Marshal.FreeBSTR(ptr);
                                    //Marshal.FreeCoTaskMem(ptr);
                                }
                            }
                        }
                    }
                }
                catch (Exception ex)
                {
                    return false;
                }
                finally
                {
                    Marshal.ReleaseComObject(profiles);
                }
            }
            return false;
        }

        public static string[] GetAvalivableInputMethodDesc(short langID)
        {
            List<string> imeList = new List<string>();
            TSF_NativeAPI.ITfInputProcessorProfiles profiles;
            if (TSF_NativeAPI.TF_CreateInputProcessorProfiles(out profiles) == 0)
            {
                try
                {
                    TSF_NativeAPI.IEnumTfLanguageProfiles enumerator = null;
                    if (profiles.EnumLanguageProfiles(langID, out enumerator) == 0)
                    {
                        if (enumerator != null)
                        {
                            TSF_NativeAPI.TF_LANGUAGEPROFILE[] langProfile = new TSF_NativeAPI.TF_LANGUAGEPROFILE[1];
                            int fetchCount = 0;
                            while (enumerator.Next(1, langProfile, out fetchCount) == 0)
                            {
                                IntPtr ptr;
                                if (profiles.GetLanguageProfileDescription(ref langProfile[0].clsid, langProfile[0].langid, ref langProfile[0].guidProfile, out ptr) == 0)
                                {
                                    bool enabled;
                                    if (profiles.IsEnabledLanguageProfile(ref langProfile[0].clsid, langProfile[0].langid, ref langProfile[0].guidProfile, out enabled) == 0)
                                    {
                                        if (enabled)
                                            imeList.Add(Marshal.PtrToStringBSTR(ptr));
                                    }
                                }
                                Marshal.FreeBSTR(ptr);
                                //in windows 2008, it will crash.
                                //Marshal.FreeCoTaskMem(ptr);
                            }
                        }
                    }
                }
                finally
                {
                    Marshal.ReleaseComObject(profiles);
                }
            }
            return imeList.ToArray();
        }

        public static string[] GetAllInputMethodDesc(short langID)
        {
            List<string> imeList = new List<string>();
            if (TSF_NativeAPI.TF_CreateInputProcessorProfiles(out var profiles) == 0)
            {
                try
                {
                    if (profiles.EnumLanguageProfiles(langID, out var enumerator) == 0)
                    {
                        if (enumerator != null)
                        {
                            TSF_NativeAPI.TF_LANGUAGEPROFILE[] langProfile = new TSF_NativeAPI.TF_LANGUAGEPROFILE[1];
                            while (enumerator.Next(1, langProfile, out var fetchCount) == 0)
                            {
                                if (profiles.GetLanguageProfileDescription(ref langProfile[0].clsid, langProfile[0].langid, ref langProfile[0].guidProfile, out var ptr) == 0)
                                {
                                    imeList.Add(Marshal.PtrToStringBSTR(ptr));
                                }
                                Marshal.FreeBSTR(ptr);
                                //in windows 2008, it will crash.
                                //Marshal.FreeCoTaskMem(ptr);
                            }
                        }
                    }
                }
                finally
                {
                    Marshal.ReleaseComObject(profiles);
                }
            }
            return imeList.ToArray();
        }

        public static string GetCurrentInputMethodDesc(short langID)
        {
            TSF_NativeAPI.ITfInputProcessorProfiles profiles;
            if (TSF_NativeAPI.TF_CreateInputProcessorProfiles(out profiles) == 0)
            {
                try
                {
                    Guid clsid;
                    Guid profileid;
                    Guid catid = new Guid(TSF_NativeAPI.GUID_TFCAT_TIP_KEYBOARD.ToByteArray());
                    if (profiles.GetDefaultLanguageProfile(langID, ref catid, out clsid, out profileid) == 0)
                    {
                        if (profiles.GetActiveLanguageProfile(ref clsid, out langID, out profileid) == 0)
                        {
                            IntPtr ptr;
                            try
                            {
                                if (profiles.GetLanguageProfileDescription(ref clsid, langID, ref profileid, out ptr) == 0)
                                {
                                    string s = Marshal.PtrToStringBSTR(ptr);
                                    Marshal.FreeBSTR(ptr);
                                    //in windows 2008 , it will carsh.
                                    //Marshal.FreeCoTaskMem(ptr);
                                    return s;
                                }
                            }
                            catch (Exception ex)
                            {
                                int i = 0;
                            }
                        }
                    }
                }
                finally
                {
                    Marshal.ReleaseComObject(profiles);
                }
            }
            return string.Empty;
        }

        public static bool DeActiveInputMethod(short langID)
        {
            List<string> imeList = new List<string>();
            TSF_NativeAPI.ITfInputProcessorProfiles profiles;
            if (TSF_NativeAPI.TF_CreateInputProcessorProfiles(out profiles) == 0)
            {
                try
                {
                    Guid clsid = Guid.Empty;
                    return profiles.ActivateLanguageProfile(ref clsid, langID, ref clsid) == 0;
                }
                finally
                {
                    Marshal.ReleaseComObject(profiles);
                }
            }
            return false;
        }
    }
}